package fr.doume.tcp.sspi;


//tomcat 5.5
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;

//tomcat 6
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.Date;
import java.net.Socket;

import java.util.Timer;
import java.util.TimerTask;
/**
 *
 * This class wraps a <c>ConcurrentLinkedQueue</c>. 
 * To reuse the TCP connections with the service Negoserver. If too many connections are open, we could have
 * too many sockets in the state TIME_WAIT ( This state is for 4 minutes).
 * The count of ports wich can be opened is not infinite.<p>
 * We add the sockets in the pool only if the translation of the roles into sids or the authentication was established.  
 * The others sockets has been closed.<br>
 * There is only one instance of this classe.
  * It is created when the singleton AuthenticationContext is created 
  */
public class ConnectionTcpPool
{
	private static Log log = LogFactory.getLog(ConnectionTcpPool.class);
  /**
  * Timelife of a socket not reused from the pool. Used before to give a socket from the pool.
  */ 
  private static final int TimeLifeSocket = 5 * 60 * 1000; // 5 minutes 
  
  /**
  * Used to define the time before to remove the too old sockets from the pool.
  */ 
  private static final int TimeLifeCancelOldConnections =  320000; //5 * 60 * 1000 + 20 * 1000 or  5 minutes + 20 seconds
     
  private ConcurrentLinkedQueue<Element> list;
  
  /**
  * Timer used to remove the old connections.
  */
  private Timer cancel = null;
  
  public ConnectionTcpPool()
  {
    list = new ConcurrentLinkedQueue<Element>();
    if (log.isDebugEnabled()) log.debug("A New ConnectionTcpPool!!");
    //cancel = new Timer();
    //cancel.schedule( new CancelOldConnections() , TimeLifeCancelOldConnections, TimeLifeCancelOldConnections);
  }
  
  /**
  * called to add a socket into the pool.
  */
  public void add (Socket s)
  {
    Element e = new Element(s);
    list.add(e);
    if (log.isDebugEnabled()) log.debug("A socket added into the list");
  }
  
  /**
  * To get a socket from the pool.
  * Verify that the the socket was not for a long timle in the pool
  */ 
  public Socket getSocket()
  {
    Element e = list.poll();
    Date now;
    while ( e != null)
    {
      if (log.isDebugEnabled()) log.debug("Element is not null");
      now = new Date();
      if ( now.getTime() - e.getDate().getTime() < TimeLifeSocket )
      {
        if (log.isDebugEnabled()) log.debug("A socket removed from the list");
        return e.getSocket();
      }
      else 
      {
        try
        {
          e.getSocket().close();
        }
        catch (Exception ex){}
      }
      e = list.poll();
    }
    if (log.isDebugEnabled()) log.debug("Send a null socket");
    return null;
  }
  /**
  * Task used to close the not used sockets. 
  */ 
  class CancelOldConnections extends TimerTask
  {
    public void run()
    {
      if (log.isDebugEnabled()) log.debug("Cancel Old Connections");
      Element e = list.peek();
      Date now;
      while (e != null)
      {
        now = new Date();
        if ( now.getTime() - e.getDate().getTime() < (TimeLifeSocket + 10000) )
        {
          return;
        }
        else 
        {
          try
          {
            if (list.remove(e) )
            {
              e.getSocket().close();
            }
            if (log.isDebugEnabled()) log.debug("A connection has been canceled");

          }
          catch (Exception ex){}
        }
        e = list.peek();
      }    
    }   
  } 
}

  /**
  * Couple socket and date. To close the sockets not reused, after a time out 
  */ 
class Element
{
  private Socket s;
  private Date d;
  public Element(Socket soc)
  {
    s = soc;
    d = new Date();
  }
  public Date getDate()
  {
    return d;
  }
  public Socket getSocket()
  {
    return s;
  }
}  
